<script setup lang="ts">
  import { ref, onMounted, watch } from 'vue';
  import { encodeHTML, filterHTML } from '/@/utils/purify';
  import { getTextFromPaste, insertHTML, fragmentFromHtml } from '/@/utils/dom';
  import type { ISimpleEditor } from './interface';

  interface ISimpleEditorProps {
    modelValue?: string;
  }
  const props = withDefaults(defineProps<ISimpleEditorProps>(), {
    modelValue: '',
  });

  const emit = defineEmits<{
    (event: 'on-created', editor: ISimpleEditor): void;
    (event: 'update:model-value', value: string): void;
    (event: 'change', value: string): void;
  }>();

  const inputElementRef = ref<HTMLElement | null>(null);
  const contentRef = ref(props.modelValue);

  const editor: ISimpleEditor = {
    setHtml: (html) => {
      if (inputElementRef.value) {
        inputElementRef.value.innerHTML = html;
        syncContent();
      }
    },
    insertHtml: (html) => {
      if (inputElementRef.value) {
        insertHTML(inputElementRef.value, html);
        syncContent();
      }
    },
    clear: () => {
      editor.setHtml('');
    },
    focus: () => {
      inputElementRef.value?.focus();
    },
    prependHtml: (html) => {
      if (inputElementRef.value) {
        const fragment = fragmentFromHtml(html);
        inputElementRef.value.prepend(fragment);
        syncContent();
      }
    },
    getEditableContainer: () => {
      return inputElementRef.value;
    },
  };

  const syncContent = () => {
    if (inputElementRef.value) {
      contentRef.value = inputElementRef.value.innerHTML;
    }
  };

  const onChange = () => {
    syncContent();
  };

  const onPaste = (event: ClipboardEvent) => {
    if (inputElementRef.value) {
      const text = getTextFromPaste(event);
      const html = filterHTML(encodeHTML(text));
      editor.insertHtml(html);
    }
  };

  watch(
    () => props.modelValue,
    () => {
      if (props.modelValue !== contentRef.value) {
        editor.setHtml(contentRef.value);
      }
    },
  );

  watch(contentRef, () => {
    emit('update:model-value', contentRef.value);
    emit('change', contentRef.value);
  });

  onMounted(() => {
    if (contentRef.value !== '') {
      editor.setHtml(contentRef.value);
    }
    emit('on-created', editor);
  });
</script>

<template>
  <div
    ref="inputElementRef"
    class="px-[12px] py-[8px] outline-none w-full resize bg-transparent"
    contenteditable="true"
    @paste.prevent="onPaste"
    @input="onChange"
  ></div>
</template>
